package personal;

import exceptions.IllegalDecimalException;
import exceptions.IllegalIdentifierException;
import personal.parser.*;
import personal.scanner.MyScanner;
import personal.scanner.ScannerDFA;
import personal.scanner.SimpleScanner;
import personal.scanner.SimpleScannerDFA;

import java.util.List;

public class SimpleFactory implements Factory {
    @Override
    public ScannerDFA makeScannerDFA() {
        SimpleScannerDFA dfa = new SimpleScannerDFA(1, "  ",
                "01  02  0  1  2  3  4  5  6  7  8  9",
                "02  02  0  1  2  3  4  5  6  7  8  9",
                "02  03  E  e",
                "02  05  .",
                "05  06  0  1  2  3  4  5  6  7  8  9",
                "06  06  0  1  2  3  4  5  6  7  8  9",
                "06  03  E  e",
                "03  04  0  1  2  3  4  5  6  7  8  9",
                "03  07  +  -",
                "07  04  0  1  2  3  4  5  6  7  8  9",
                "04  04  0  1  2  3  4  5  6  7  8  9",

                "01  08  t",
                "08  09  r",
                "09  10  u",
                "10  11  e",
                "01  12  f",
                "12  13  a",
                "13  14  l",
                "14  10  s",

                "01  15  +  -  *  /  ^  ?  :",
                "01  16  >",
                "16  17  =",
                "01  18  <",
                "18  17  =  >",
                "01  19  =",
                "01  20  !  &  |",
                "01  21  (  )  ,",

                "01  22  s",
                "22  23  i",
                "23  24  n",
                "01  25  m",
                "25  23  i",
                "25  26  a",
                "26  24  x",
                "01  27  c",
                "27  28  o",
                "28  24  s"
        );

        dfa.registerAcceptableNode(2, MyScanner.DecimalToken.class);
        dfa.registerAcceptableNode(4, MyScanner.DecimalToken.class);
        dfa.registerAcceptableNode(6, MyScanner.DecimalToken.class);
        dfa.registerAcceptableNode(11, MyScanner.BooleanToken.class);

        dfa.registerAcceptableNode(15, MyScanner.ArithmeticOperatorToken.class);

        dfa.registerAcceptableNode(16, MyScanner.CompareOperatorToken.class);
        dfa.registerAcceptableNode(17, MyScanner.CompareOperatorToken.class);
        dfa.registerAcceptableNode(18, MyScanner.CompareOperatorToken.class);
        dfa.registerAcceptableNode(19, MyScanner.CompareOperatorToken.class);

        dfa.registerAcceptableNode(20, MyScanner.LogicalOperatorToken.class);

        dfa.registerAcceptableNode(21, MyScanner.DelimiterOperatorToken.class);

        dfa.registerAcceptableNode(24, MyScanner.FunctionToken.class);


        dfa.registerDefaultException(1, IllegalIdentifierException.class); // 开头就错，说明是非法字符
        // 错误的运算数字
        dfa.registerDefaultException(3, IllegalDecimalException.class);
        dfa.registerDefaultException(5, IllegalDecimalException.class);
        dfa.registerDefaultException(7, IllegalDecimalException.class);
        dfa.registerDefaultException(8, IllegalDecimalException.class);
        dfa.registerDefaultException(9, IllegalDecimalException.class);
        dfa.registerDefaultException(10, IllegalDecimalException.class);
        dfa.registerDefaultException(12, IllegalDecimalException.class);
        dfa.registerDefaultException(13, IllegalDecimalException.class);
        dfa.registerDefaultException(14, IllegalDecimalException.class);
        // 错误的标识符
        dfa.registerDefaultException(22, IllegalIdentifierException.class);
        dfa.registerDefaultException(23, IllegalIdentifierException.class);
        dfa.registerDefaultException(25, IllegalIdentifierException.class);
        dfa.registerDefaultException(26, IllegalIdentifierException.class);
        dfa.registerDefaultException(27, IllegalIdentifierException.class);
        dfa.registerDefaultException(28, IllegalIdentifierException.class);

        return dfa;
    }

    @Override
    public MyScanner makeScanner() {
        return new SimpleScanner(this.makeScannerDFA());
    }


    @Override
    public Grammar makeGrammar() {

        List<String> nonTerminalSymbolExpressions = List.of("Expr", "ArithExpr", "BoolExpr", "UnaryFunc", "VariablFunc", "ArithExprList");
        List<String> terminalSymbolExpressions = List.of(
                "decimal", "true", "false",
                "+", "-", "*", "/", "^", "neg",
                "?", ":",
                "(", ")", ",",
                "sin", "cos", "max", "min",
                ">", ">=", "<", "<=", "=", "<>",
                "&", "|", "!",
                "$"
        );
        SimpleGrammar grammar = new SimpleGrammar("Expr", nonTerminalSymbolExpressions, terminalSymbolExpressions, "  ",
                "Expr  ArithExpr",
                "ArithExpr  decimal",
                "ArithExpr  (  ArithExpr  )",
                "ArithExpr  ArithExpr  +  ArithExpr",
                "ArithExpr  ArithExpr  -  ArithExpr",
                "ArithExpr  ArithExpr  *  ArithExpr",
                "ArithExpr  ArithExpr  /  ArithExpr",
                "ArithExpr  ArithExpr  ^  ArithExpr",
                "ArithExpr  neg  ArithExpr",
                "ArithExpr  BoolExpr  ?  ArithExpr  :  ArithExpr",
                "ArithExpr  UnaryFunc",
                "ArithExpr  VariablFunc",
                "UnaryFunc  sin  (  ArithExpr  )",
                "UnaryFunc  cos  (  ArithExpr  )",
                "VariablFunc  max  (  ArithExpr  ,  ArithExprList  )",
                "VariablFunc  min  (  ArithExpr  ,  ArithExprList  )",
                "ArithExprList  ArithExpr",
                "ArithExprList  ArithExpr  ,  ArithExprList",
                "BoolExpr  true",
                "BoolExpr  false",
                "BoolExpr  (  BoolExpr  )",
                "BoolExpr  ArithExpr  >  ArithExpr",
                "BoolExpr  ArithExpr  >=  ArithExpr",
                "BoolExpr  ArithExpr  <  ArithExpr",
                "BoolExpr  ArithExpr  <=  ArithExpr",
                "BoolExpr  ArithExpr  =  ArithExpr",
                "BoolExpr  ArithExpr  <>  ArithExpr",
                "BoolExpr  BoolExpr  &  BoolExpr",
                "BoolExpr  BoolExpr  |  BoolExpr",
                "BoolExpr  !  BoolExpr"
        );
        return grammar;
    }

    @Override
    public ParserTable makeParserTable() {
        Grammar grammar = this.makeGrammar();
        OperatorTable operatorTable = new OperatorTable(grammar, "  ",
                "(  1  LEFT",
                ")  1  LEFT",
                "sin  2  LEFT",
                "cos  2  LEFT",
                "max  2  LEFT",
                "min  2  LEFT",
                "neg  3  RIGHT",
                "^  4  RIGHT",
                "*  5  LEFT",
                "/  5  LEFT",
                "+  6  LEFT",
                "-  6  LEFT",
                ">  7  LEFT",
                ">=  7  LEFT",
                "<  7  LEFT",
                "<=  7  LEFT",
                "=  7  LEFT",
                "<>  7  LEFT",
                "!  8  RIGHT",
                "&  9  LEFT",
                "|  10  LEFT",
                "?  11  RIGHT",
                ":  11  RIGHT"
        );
//        System.out.println(operatorTable);
        return new SimpleParserTable(grammar, operatorTable);
    }

    @Override
    public MyParser makeParser() {
        return new SimpleParser(this.makeParserTable());
    }
}
